home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’94 / [√] Distribution Restricted! / Steve Sisak / TMFutures / AEThreads.c next >
Text File  |  1994-06-26  |  6KB  |  254 lines

  1. /*
  2.     File:        AEThreads.c
  3.  
  4.     Contains:    xxx put contents here xxx
  5.  
  6.     Written by:    xxx put writers here xxx
  7.  
  8.     Copyright:    © 1994 Steve Sisak, all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.  
  13. */
  14.  
  15. #ifndef __AETHREADS__
  16. #include "AEThreads.h"
  17. #endif
  18. #ifndef __UFAILURE__
  19. #include "UFailure.h"
  20. #endif
  21. #ifndef __ERRORS__
  22. #include <Errors.h>
  23. #endif
  24. #include <AppleEvents.h>
  25.  
  26. typedef struct AEThreadDesc  AEThreadDesc;
  27. typedef struct AEThreadParam AEThreadParam;
  28.  
  29. struct AEThreadDesc                    // Kept in the OS refcon
  30. {
  31.     AEEventHandlerUPP    handler;    // The real handler
  32.     long                refcon;        // The real refcon
  33.     Size                stackSize;    // Stack size for handling event
  34.     ThreadOptions        options;    // Thread options for event
  35.     ThreadID            holder;        // used as a semaphore
  36. };
  37.  
  38. struct AEThreadParam                // Used in spawning
  39. {
  40.     const AppleEvent*    event;
  41.     AppleEvent*            reply;
  42.     AEThreadDesc*        desc;
  43.     ThreadID            thread;
  44.     OSErr                result;
  45. };
  46.  
  47. pascal void        SwapTopHandler(ThreadID threadBeingSwitched, void *switchProcParam);
  48. pascal OSErr    SpawnAEThread(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon);
  49. pascal long        AEThread(AEThreadParam* parms);
  50.  
  51. AEEventHandlerUPP gSpawnAEThreadUPP = nil;
  52.  
  53. #pragma segment foobar
  54.  
  55. pascal OSErr AEInstallThreadedEventHandler(
  56.     AEEventClass            theAEEventClass,
  57.     AEEventID                theAEEventID,
  58.     AEEventHandlerProcPtr    proc,
  59.     long                    handlerRefcon,
  60.     ThreadOptions            options,
  61.     Size                    stacksize)
  62. {
  63.     AEThreadDesc* desc = (AEThreadDesc*) NewPtr(sizeof(AEThreadDesc));
  64.     OSErr          err  = MemError();
  65.     
  66.     if (gSpawnAEThreadUPP == nil)
  67.     {
  68.         gSpawnAEThreadUPP = NewAEEventHandlerProc(SpawnAEThread);
  69.     }
  70.     
  71.     if (err == noErr)
  72.     {
  73.         desc->handler    = NewAEEventHandlerProc(proc);
  74.         desc->refcon    = handlerRefcon;
  75.         desc->stackSize    = stacksize;
  76.         desc->options    = options;
  77.         desc->holder    = kNoThreadID;
  78.  
  79.         err = AEInstallEventHandler(theAEEventClass, theAEEventID, gSpawnAEThreadUPP, (long) desc, false);
  80.     }
  81.     
  82.     return err;
  83. }
  84.  
  85. #pragma segment AEThread
  86.  
  87. pascal void AEThreadTerminator(ThreadID threadTerminated, void *terminationProcParam);
  88. pascal void AEThreadTerminator(ThreadID threadTerminated, void *terminationProcParam)
  89. {
  90.     FailInfo        fi;    
  91.     FailInfoPtr        oldTopHandler = gTopHandler;    // save current handler
  92.     FailInfoPtr        newTopHandler = * (FailInfoPtr*) terminationProcParam;
  93.  
  94. Debugger();
  95.     
  96.     if (newTopHandler != nil)
  97.     {
  98.         gTopHandler = newTopHandler;                // point to top of thread's handlers
  99.         
  100.         while (newTopHandler->nextInfo != nil)        // find bottom handler
  101.         {
  102.             newTopHandler = newTopHandler->nextInfo;
  103.         }
  104.         
  105.         newTopHandler->nextInfo = &fi;                // now splice fi in below it
  106.         if (setjmp(fi.savedState) == 0)
  107.         {
  108.             Failure(userCanceledErr, 0);            // and trip the handlers
  109.         }
  110.  
  111.         gTopHandler = oldTopHandler;    // restore top handler
  112.     }
  113. }
  114.  
  115.  
  116. pascal void SwapTopHandler(ThreadID threadBeingSwitched, void *switchProcParam)
  117. {
  118.     FailInfoPtr* save = (FailInfoPtr*) switchProcParam;
  119.     FailInfoPtr     temp = *save;
  120.     *save          = gTopHandler;
  121.     gTopHandler = temp;
  122. }
  123.  
  124. pascal long AEThread(AEThreadParam* parms)
  125. {
  126.     AppleEvent        event;            // Original parameters we care about
  127.     AppleEvent        reply;
  128.     AEThreadDesc*    desc;
  129.     FailInfoPtr     myTopHandler;    // Used to save the inactive failure handler
  130.     FailInfo        fi;
  131.     OSErr            err;
  132.  
  133.     event = *parms->event;            // copy these into our own stack frame
  134.     reply = *parms->reply;
  135.     desc  =  parms->desc;
  136.     
  137.     myTopHandler = gTopHandler;        // Save global failure handler
  138.     gTopHandler  = nil;                // don't let failures propagate outside
  139.  
  140.     Try (fi)
  141.     {
  142.         // We need to make sure that the gTopHandler switches in and out with our thread
  143.         
  144.         FailOSErr(SetThreadSwitcher(kCurrentThreadID, SwapTopHandler, &myTopHandler, true));
  145.         FailOSErr(SetThreadSwitcher(kCurrentThreadID, SwapTopHandler, &myTopHandler, false));
  146. //        FailOSErr(SetThreadTerminator(kCurrentThreadID, AEThreadTerminator, &myTopHandler));
  147.  
  148.         
  149.         
  150.         FailOSErr(AESuspendTheCurrentEvent(&event));
  151.  
  152.         parms->result = noErr;        // Let caller know we're ready
  153.         Success(&fi);
  154.     }
  155.     else
  156.     {
  157.         parms->result = fi.error;
  158.         return nil;
  159.     }
  160.  
  161.     // At this point, we need to let our caller return
  162.  
  163.     while (desc->holder != kNoThreadID)
  164.     {
  165.         YieldToThread(desc->holder);
  166.     }
  167.  
  168.     // We are now on our own
  169.     
  170.     Try (fi)
  171.     {
  172.         FailOSErr(CallAEEventHandlerProc(desc->handler, &event, &reply, desc->refcon));
  173.         Success(&fi);
  174.     }
  175.     else
  176.     {
  177.         // Since the event was suspended, we need to stuff the error code ourselves    
  178.         // note that there's not much we can do about reporting errors beyond here
  179.         
  180.         err = AEPutAttributePtr(&reply, keyErrorNumber, typeShortInteger, &fi.error, sizeof(fi.error));
  181.  
  182.     #if qDebug
  183.         if (err)
  184.             ProgramBreak("\pAEPutAttributePtr failed installing error code - very bad");
  185.     #endif
  186.     }
  187.     
  188.     err = AEResumeTheCurrentEvent(&event, &reply, kAENoDispatch, 0);    // This had better work
  189.  
  190. #if qDebug
  191.     if (err)
  192.         ProgramBreak("\pAEResumeTheCurrentEvent failed - very bad");
  193. #endif
  194.  
  195.     gTopHandler     = myTopHandler;    // Restore global failure handler
  196.     myTopHandler = nil;                // Keep terminator from firing handlers
  197.     
  198.     return fi.error;
  199. }
  200.  
  201. #pragma segment Spawn
  202.  
  203. pascal OSErr SpawnAEThread(const AppleEvent *event, AppleEvent *reply, long handlerRefcon)
  204. {
  205.     AEThreadParam param;
  206.     
  207.     param.event  = event;
  208.     param.reply  = reply;
  209.     param.desc     = (AEThreadDesc*) handlerRefcon;
  210.     param.thread = kNoThreadID;
  211.  
  212.     if (!param.desc)
  213.     {
  214.         param.result = paramErr;
  215.     }
  216.     else
  217.     {
  218.         while (param.desc->holder != kNoThreadID)    // make sure no-one else is trying to start a handler
  219.         {
  220.             YieldToAnyThread();
  221.         }
  222.         
  223.         if ((param.result = GetCurrentThread(¶m.desc->holder)) == noErr)    // Grab the semaphore
  224.         {
  225.             param.result = NewThread(kCooperativeThread,
  226.                             (ThreadEntryProcPtr) &AEThread,
  227.                             ¶m,
  228.                             param.desc->stackSize,
  229.                             param.desc->options,
  230.                             nil,
  231.                             ¶m.thread);
  232.             
  233.             if (param.result == noErr)
  234.             {
  235.                 param.result = 1;
  236.             
  237.                 do
  238.                 {
  239.                     YieldToThread(param.thread);
  240.                 }
  241.                 while (param.result == 1);    // Wait for thread to pick up parameters
  242.             }
  243.         }
  244.         
  245.         param.desc->holder = kNoThreadID;    // release any claims we have
  246.     }
  247.     
  248.     return param.result;
  249. }
  250.  
  251.  
  252.  
  253.  
  254.